Open RStudio and go to:
File > New Project... > New Directory > Shiny Web Application > Enter a directory name and location > Create project
R will open a new project for the shiny app, which will contain one file (app.R), which will have an example shiny app that you can run by clicking the Run App button (top right of the script panel).
This is the home of your app, and any data, pictures, etc. you need for your app to run need to be stored in the same directory so that they can be accessed by the app once it is deployed.
Note: Make sure you have shiny installed.
install.packages("shiny")
You can download a copy of this workshop, and all the code here. After downloading the file, you can unzip it and then launch the project file (CanDev_2022.Rproj) in RStudio.
app.R has three components:
shinyApp() functionYou can include other code inside your app (e.g., reading data, loading packages, creating static variables). This code is run once (when the app is started), and never again.
The user interface (ui) object controls the layout and appearance of your app. The server function contains the instructions that a computer needs to build the app. Finally, the shinyApp function creates the Shiny app from an explicit UI/server pair.
Here is a high level overview of a shiny app (we will cover each part in more specifics later on):
Shiny is about making it easy to wire up input values from a web page, making them available to you in R, and have the results of your R code be written as output values back out to the web page.
The reactivity framework used by shiny means that:
You can copy and paste almost all of the code in this workshop into your R console to launch a shiny app. Please ensure that you have installed the required packages.
install.packages("shiny")
Here is the basic skeleton of a shiny app:
library(shiny)
# Any code that should be executed once when the app starts. E.g., reading in a
# data file, creating static environment variables.
# Code that creates the UI of the app
ui <- fluidPage(
# Title for your app
titlePanel(),
sidebarLayout(
# Generally, inputs are put into the sidebar
sidebarPanel(
# Inputs go here
),
# And outputs are put into the mainPanel
mainPanel(
# Outputs go here
)
)
)
# The server takes inputs from the webpage, updates outputs, and send the
# outputs back to the webpage
server <- function(input, output) {
# Server code goes here
}
# Used to launch the app after defining the UI and server.
shinyApp(ui, server)
There are other templates you can use as well; but a fluid page with a sidebar layout is a good option. Fluid pages will reflow content in case there isn’t enough horizontal space. The sidebar layouts separates the page into two panels (sidebar and main), making it easier to organize inputs and outputs.
With functions like fluidRow() and column() you can have more control over the layout of an app, but for the moment we will just arrange the app into the sidebar and main panel.
Aside from reactive elements, you might also want to include static elements in your UI. Static elements are things like text, or images that do not change with user input. Common tags are available from the shiny package (div(), h1(), a(), br()). Less common tags can be inserted with the tags object (e.g., tags$abbr(), tags$figcaption()).
Here is an example app with just static content:
library(shiny)
# Any code that should be executed once when the app starts. E.g., reading in a
# data file, creating static environment variables.
# Code that creates the UI of the app
ui <- fluidPage(# Title for your app
titlePanel("A first level heading title"),
sidebarLayout(
# Generally, inputs are put into the sidebar
sidebarPanel(
h2("A second level heading"),
"This small Shiny application demonstrates some static UI elements."
),
# And outputs are put into the mainPanel
mainPanel(
h2("A second level header in the main panel"),
p('My first paragraph, with some ', strong('bold'), ' text.')
)
)
)
# The server takes inputs from the webpage, updates outputs, and send the
# outputs back to the webpage
server <- function(input, output) {
# Because the app is static, there is no server code!
}
# Used to launch the app after defining the UI and server.
shinyApp(ui, server)
Until now, the apps have been simple and contained mostly static elements that we created in the UI. Shiny, however, is all about making things interactive. We do this by using inputs and outputs.
*Input() function| Function | Collects |
|---|---|
actionButton() |
A button press |
checkboxInput() |
The state of a check box (TRUE/FALSE) |
checkboxGroupInput() |
The state of a group of check boxes (a vector of selected values) |
dateInput() |
A single date |
dateRangeInput() |
A range of dates (a vector of the min and max date) |
fileInput() |
A file |
numericInput() |
A numeric value |
passwordInput() |
A password |
radioButtons() |
The state of a group of radio buttons (Which option is selected) |
selectInput() |
The current selection(s) for a drop-down list (vector of length 1, or more, that includes only selected values) |
sliderInput() |
A single number/date/date time or a range of the same (a single value, or a vector of the min and max) |
textInput() |
A character string (a vector of the entered text) |
*Input(inputId, label, ...)
When using a sidebarLayout() I typically place most of the inputs into the sidebarPanel and use the mainPanel for my outputs. Notice that the different inputs are separated with commas inside of the sidebarPanel.
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(actionButton("actionbutton", "Action Button"),
checkboxInput("checkboxInput", "Check box", value = TRUE),
checkboxGroupInput("checkboxGroupInput", "Check box group", choices = c("A", "B", "C")),
dateInput("dateInput", "Date"),
dateRangeInput("dateRangeInput", "Date Range"),
fileInput("fileInput", "File"),
numericInput("numericInput", "Number", value = 10),
passwordInput("passwordInput", "Password"),
radioButtons("radioButtons", "Radio Buttons", choices = c("A", "B", "C")),
selectInput("selectInput", "Drop down", choices = c("A", "B", "C")),
sliderInput("sliderInput", "Silder", min = 1, max = 10, value = 5),
textInput("textInput", "Text")
),
mainPanel(
)
)
)
server <- function(input, output) { }
shinyApp(ui, server)
*Output() functions.| Function | Inserts |
|---|---|
dataTableOutput() |
An interactive table |
tableOutput() |
A table |
imageOutput() |
An image |
plotOutput() |
A plot |
textOutput() |
Text |
verbatimTextOutput() |
Text |
uiOutput() |
a Shiny UI element |
htmlOutput() |
Raw HTML |
*Output(outputId, ...)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(),
mainPanel(
dataTableOutput("dataTableOutput"),
tableOutput("tableOutput"),
plotOutput("plotOutput"),
textOutput("textOutput"),
verbatimTextOutput("verbatimTextOutput"),
uiOutput("uiOutput")
)
)
)
server <- function(input, output) {
output$dataTableOutput <- renderDataTable({ iris })
output$tableOutput <- renderTable({ iris })
output$plotOutput <- renderPlot({ plot(iris) })
output$textOutput <- renderText({ "Some rendered text" })
output$verbatimTextOutput <- renderText({ "Some rendered text" })
output$uiOutput <- renderUI({ selectInput("input", "A rendered UI input", choices = c("A", "B", "C")) })
}
shinyApp(ui, server)
output object (output$outputId), and the UI has a corresponding entry for each IDAfter creating a place in the UI for the output, you need to write the code to create the output. The outputs always need to be saved into the output object. This looks like:
server <- function(input, output) {
output$outputId <- # code to create the output, e.g., code that can make a plot, or a table
}
Every output in the UI needs to have a value created in the server
plotOutput("plot") and tableOutput("table") in the UI, you need output$plot and output$table in the server.For an output to be displayed by the webpage, it must be rendered, which means it must be converted into HTML that the webpage can display. Which function you use to render an output depends on its type.
| Function | Creates |
|---|---|
renderDataTable() |
An interactive table |
renderTable() |
A table |
renderPlot() |
A plot |
renderText() |
A character string |
renderUI() |
A Shiny UI element |
server <- function(input, output) {
output$plot <- renderPlot({
plot(iris)
})
output$table <- renderDataTable({
iris
})
# The same table but rendered as a static table.
# output$table <- renderTable({
# iris
# })
}
To make outputs interactive, you need to connect them to one or more inputs. The simplest way to do this is to filter the data using the input values. This lets you take static data (like the iris data frame) and transform it into reactive data which can drive outputs.
library(shiny)
library(tidyverse)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# the slider input will return a number between 1 and 100
sliderInput("n", "Number", min = 1, max = 100, value = 10),
# the select input will return a vector of all the selected species.
selectInput("species", "Species",
choices = unique(iris$Species),
selected = unique(iris$Species),
# We are letting the user select multiple values
multiple = TRUE)
),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output) {
output$table <- renderTable({
iris %>%
# because species can be a vector of length 1 - 3, we will use the %in%
# operator to compare
filter(Species %in% input$species) %>%
# n will always be a single value
head(., n = input$n)
})
}
shinyApp(ui, server)
You can share a shiny app with anyone who has R and the required packages installed on their computer simply by sharing the code, and other required files, with them.
If you want to share a shiny app with the public, or someone who doesn’t have R and the required packages, you need to deploy your app to a shiny server. Shinyapps.io provides a free service that lets you upload a limited number of apps (there are paid plans with more active hours that allow for more apps to be loaded). You can look at this article for details on deploying apps to Shinyapps.io.
To run this code, please clone the project using the instructions above.
runApp()
You can look at the source code for the shiny app in CanDev_2022/app.R.
CanDev_2022/Data and does some preprocessinginput$year), one multiple choice select input (input$category) and two single choice select inputs (input$coc, input$NAICS)"plot") and one table output ("table")output$plot
renderPlot({ # Code that returns a plot}) function we can turn code that creates a plot into an output that we can displayoutput$table
renderDataTable({ # Code that returns a table}) function we can turn code that creates a table (or table like object) into an output that we can display